package jnpf.wx;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

public class PayerSubAccountManager {

    // 替换为实际的签约编码
    private static final String MERCHANT_NO = "01202507241711050000";
    // 替换为实际的商户号
    private static final String PLATFORM_ID = "0100202507105302";
    // 接口地址
    private static final String SUB_ACCOUNT_MANAGE_URL = "https://wxpay.cmbc.com.cn/mobilePlatform/bill/samPayerSubAcctManage.do";
    // 替换为实际的密钥
    private static final String API_KEY = "your_actual_api_key";

    /**
     * 生成API请求的签名
     * @param requestBody 请求的JSON字符串
     * @return 包含签名信息的Authorization头部值
     */
    public static String generateAuthorizationHeader(String requestBody) {
        String sign = generateSignature(requestBody, API_KEY);
        return MERCHANT_NO + " " + sign;
    }

    /**
     * 生成签名值
     * @param requestBody 请求的JSON字符串
     * @param secretKey 密钥
     * @return MD5签名值(32位大写)
     */
    public static String generateSignature(String requestBody, String secretKey) {
        try {
            // 拼接body和key（按接口要求的签名规则）
            String content = requestBody + secretKey;
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(content.getBytes("UTF-8"));
            byte[] digest = md.digest();
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(0xFF & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString().toUpperCase();
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            throw new RuntimeException("生成签名失败", e);
        }
    }

    /**
     * 生成外部操作流水号（32位唯一）
     */
    private static String generateMerSerialNo() {
        return UUID.randomUUID().toString().replace("-", "") +
                UUID.randomUUID().toString().replace("-", "").substring(0, 8);
    }

    /**
     * 付款方子账簿管理接口调用
     * @param operType 操作类型（01-新增、02-修改、03-注销）
     * @param partnerName 付款方子账簿名称（新增时必输）
     * @param accNo 子账簿账号（修改和注销时必输）
     * @param stat 子账簿状态（仅修改时可输入）
     * @param accName 联系人名称（新增时必输）
     * @param phoneId 手机号（新增时必输）
     * @param mail 邮箱
     * @param isPush 推送通知
     * @param storeAccNo 所属门店子账簿账号
     * @param summary 备注
     * @param isBindAcct 精准收款
     * @param bindAcctName 付款账户名称
     * @param bindAcctNo 付款账户账号
     * @param bindPostscript 客户附言
     * @param payeeAmt 单笔金额
     * @param onceLmtAmt 单笔上限金额
     * @param quotaAmt 累计上限金额
     * @param makeZero 已累计入账金额清零
     * @return 接口响应JSON字符串
     */
    public static String manageSubAccount(String operType, String partnerName, String accNo,
                                          String stat, String accName, String phoneId,
                                          String mail, String isPush, String storeAccNo,
                                          String summary, String isBindAcct, String bindAcctName,
                                          String bindAcctNo, String bindPostscript, String payeeAmt,
                                          String onceLmtAmt, String quotaAmt, String makeZero) {
        // 1. 构建请求参数
        JSONObject requestData = new JSONObject();
        // 必传参数
        requestData.put("merchantNo", MERCHANT_NO);
        requestData.put("platformId", PLATFORM_ID);
        requestData.put("merSerialNo", MerSerialNoUtils.getFlowMchSeqNo());
        requestData.put("operType", operType);

        // 根据操作类型处理参数
        if ("01".equals(operType)) {
            // 新增操作必传参数
            requestData.put("partnerName", partnerName);
            requestData.put("accName", accName);
            requestData.put("phoneId", phoneId);
        } else if ("02".equals(operType)) {
            // 修改操作必传参数
            requestData.put("accNo", accNo);
            // 非空参数才添加（不输入则置空）
            if (partnerName != null) {
                requestData.put("partnerName", partnerName);
            }
            if (accName != null) {
                requestData.put("accName", accName);
            }
            if (phoneId != null) {
                requestData.put("phoneId", phoneId);
            }
        } else if ("03".equals(operType)) {
            // 注销操作只上送子账簿账号
            requestData.put("accNo", accNo);
        }

        // 可选参数（非空才添加）
        if (stat != null && !stat.isEmpty()) {
            requestData.put("stat", stat);
        }
        if (mail != null && !mail.isEmpty()) {
            requestData.put("mail", mail);
        }
        if (isPush != null && !isPush.isEmpty()) {
            requestData.put("isPush", isPush);
        }
        if (storeAccNo != null && !storeAccNo.isEmpty()) {
            requestData.put("storeAccNo", storeAccNo);
        }
        if (summary != null && !summary.isEmpty()) {
            requestData.put("summary", summary);
        }
        if (isBindAcct != null && !isBindAcct.isEmpty()) {
            requestData.put("isBindAcct", isBindAcct);
        }
        if (bindAcctName != null && !bindAcctName.isEmpty()) {
            requestData.put("bindAcctName", bindAcctName);
        }
        if (bindAcctNo != null && !bindAcctNo.isEmpty()) {
            requestData.put("bindAcctNo", bindAcctNo);
        }
        if (bindPostscript != null && !bindPostscript.isEmpty()) {
            requestData.put("bindPostscript", bindPostscript);
        }
        if (payeeAmt != null && !payeeAmt.isEmpty()) {
            requestData.put("payeeAmt", payeeAmt);
        }
        if (onceLmtAmt != null && !onceLmtAmt.isEmpty()) {
            requestData.put("onceLmtAmt", onceLmtAmt);
        }
        if (quotaAmt != null && !quotaAmt.isEmpty()) {
            requestData.put("quotaAmt", quotaAmt);
        }
        if (makeZero != null && !makeZero.isEmpty()) {
            requestData.put("makeZero", makeZero);
        }

        // 2. 生成请求体JSON字符串
        String requestBody = requestData.toString();
        System.out.println("请求体：" + requestBody);


        // 4. 发送POST请求并返回响应
        return sendManageRequest(requestBody);
    }

    public static String sendManageRequest(String requestBody) {
        // 1. 校验请求体非空
        if (requestBody == null || requestBody.trim().isEmpty()) {
            throw new IllegalArgumentException("请求体不能为空（JSON报文缺失）");
        }

        // 2. 校验请求体为有效JSON
        if (!isValidJson(requestBody)) {
            throw new IllegalArgumentException("请求体不是有效的JSON格式：" + requestBody);
        }

        try {
            // 3. 按工具类流程执行：getSign → sign → encrypt
            // 3.1 生成签名原文（getSign方法）
            String sign = SignEncryptDncryptSignChk.getSign(requestBody);
            System.out.println("--------------------------------------");
            System.out.println("1. 签名原文（getSign）：");
            System.out.println(sign);

            // 3.2 用私钥加签（sign方法：参数为签名原文+业务内容）
            String signContext = SignEncryptDncryptSignChk.sign(sign, requestBody);
            System.out.println("--------------------------------------");
            System.out.println("2. 加签后内容（sign）：");
            System.out.println(signContext);


            // 3.4 用银行公钥加密明文JSON（encrypt方法）
            String encryptContext = SignEncryptDncryptSignChk.encrypt(signContext);
            System.out.println("--------------------------------------");
            System.out.println("4. 加密后内容（encrypt）：");
            System.out.println(encryptContext);

            // 4. 构建公共报文头（请求体中的顶层结构，含businessContext）
            // 这里的"公共报文头"指的是请求体（Body）中的顶层JSON结构
            JSONObject requestBodyPublicHeader = new JSONObject();
            requestBodyPublicHeader.put("businessContext", encryptContext);  // 核心：businessContext放在请求体的顶层
            String requestJson = requestBodyPublicHeader.toString();
            System.out.println("--------------------------------------");
            System.out.println("5. 最终请求体（含公共报文头）：");
            System.out.println(requestJson);  // 格式为: {"businessContext":"加密后的内容"}

            // 5. 发送HTTP请求
            try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
                HttpPost httpPost = new HttpPost(SUB_ACCOUNT_MANAGE_URL);

                // 请求头（Headers）仅包含Content-Type，不包含businessContext
                httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");

                // 请求体（Body）设置为包含businessContext的公共报文结构
                StringEntity entity = new StringEntity(requestJson, StandardCharsets.UTF_8);
                httpPost.setEntity(entity);

                // 6. 接收响应并处理
                try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                    int statusCode = response.getStatusLine().getStatusCode();
                    System.out.println("--------------------------------------");
                    System.out.println("6. 响应状态码：" + statusCode);

                    HttpEntity responseEntity = response.getEntity();
                    if (responseEntity != null) {
                        String responseBody = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
                        System.out.println("--------------------------------------");
                        System.out.println("7. 原始响应内容：");
                        System.out.println(responseBody);

                        // 7. 从响应体中提取businessContext（响应体也是JSON结构）
                        JSONObject responseJson = JSONObject.parseObject(responseBody);
                        String responseCipher = responseJson.getString("businessContext");
                        System.out.println("--------------------------------------");
                        System.out.println("8. 响应体中的businessContext：");
                        System.out.println(responseCipher);

                        // 8. 解密响应
                        String dncryptContext = SignEncryptDncryptSignChk.dncrypt(responseCipher);
                        System.out.println("--------------------------------------");
                        System.out.println("9. 解密后内容：");
                        System.out.println(dncryptContext);

                        // 9. 验证签名
                        String signChkResult = SignEncryptDncryptSignChk.signCheck(dncryptContext);
                        System.out.println("--------------------------------------");
                        System.out.println("10. 签名验证结果：");
                        System.out.println(signChkResult);

                        return dncryptContext;
                    }

                }
            }
        } catch (Exception e) {
            throw new RuntimeException("子账簿管理请求失败：" + e.getMessage(), e);
        }

        return null;
    }



    /**
     * 从响应中提取businessContext字段（符合民生API公共接口规范）
     */
    private static String extractBusinessContext(String responseBody) {
        try {
            JSONObject json = new JSONObject(responseBody.isEmpty());
            // 公共接口响应的密文统一放在businessContext字段（文档要求）
            return json.getString("businessContext");
        } catch (Exception e) {
            throw new RuntimeException("解析响应businessContext失败，响应格式异常：" + responseBody, e);
        }
    }


    // 辅助方法：简单校验JSON格式（判断首尾是否为{}或[]）
    private static boolean isValidJson(String json) {
        json = json.trim();
        return (json.startsWith("{") && json.endsWith("}"))
                || (json.startsWith("[") && json.endsWith("]"));
    }


    // 示例用法
    public static void main(String[] args) {
        try {
            // 示例：新增子账簿
            String result = manageSubAccount(
                    "01",                  // 操作类型：新增
                    "测试子账簿",           // 子账簿名称
                    "",                    // 新增时子账簿账号为空
                    "",                    // 新增时状态为空
                    "张三",                // 联系人名称
                    "17623369691",         // 手机号
                    "109338533@qq.com",    // 邮箱
                    "01",                  // 推送通知：短信
                    "",                    // 所属门店子账簿账号
                    "测试新增子账簿",       // 备注
                    "00",                  // 精准收款：否
                    "",                    // 付款账户名称
                    "",                    // 付款账户账号
                    "",                    // 客户附言
                    "",                    // 单笔金额
                    "",                    // 单笔上限金额
                    "",                    // 累计上限金额
                    ""                     // 累计金额清零
            );
            System.out.println("子账簿管理结果：" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}